/*-
 * Scala grammar with AST output.
 *
 * Copyright (c) 2010 Alex Suhan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer
 * in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

grammar ScalaTreeBuilder;

options {
    output = AST;
    ASTLabelType = CommonTree;
    memoize = true;
}

tokens {
    FeatureAttrib;
    FeatureMethod;
    LocalVar;
    Class;
    DiceProgram;
    SelfMethodCall;
    FormalParams;
    BaseClass;
    MethodBody;
    Body;
    CallingObject;
    CalledMethod;
    InitExpr;
    IfThenElse;
    While;
    TrueBranch;
    FalseBranch;
    CondExpr;
    Name;
    Type;
    Init;
    Formal;
    Features;
}

program
    :    (classDef SEMICOLON)+ -> ^(DiceProgram classDef+) ;

classDef
    :    KW_CLASS t1=ID (KW_EXTENDS t2=ID)? LEFT_BRACE (feature SEMICOLON)* RIGHT_BRACE ->
        ^(Class ^(Name $t1) ^(BaseClass $t2)? ^(Features feature*))
    ;

feature
    :    KW_VAR name=ID COLON type=ID (AS expr)? ->
        ^(FeatureAttrib ^(Name $name) ^(Type $type) ^(InitExpr expr)?)
    |    KW_OVERRIDE? KW_DEF name=ID LPAREN formal? (COMMA formal)* RPAREN (COLON type=ID)? AS expr ->
        ^(FeatureMethod KW_OVERRIDE? ^(Name $name) ^(Type $type)? ^(FormalParams formal*) ^(MethodBody expr))
    ;

formal
    :    name=ID COLON type=ID -> ^(Formal ^(Name $name) ^(Type $type)) ;

atom
    :    LPAREN! expr RPAREN!
    |    L_INT
    |    L_STRING
    |    KW_TRUE
    |    KW_FALSE
    |    KW_NEW^ ID
    |    (ID LPAREN) => tail -> ^(SelfMethodCall tail)
    |    KW_THIS
    |    ID
    |    LEFT_BRACE (expr SEMICOLON)+ RIGHT_BRACE -> ^(LEFT_BRACE expr+)
    |    KW_IF cond=expr etrue=expr KW_ELSE efalse=expr ->
        ^(IfThenElse ^(CondExpr $cond) ^(TrueBranch $etrue) ^(FalseBranch $efalse))
    |    KW_WHILE cond=expr body=expr ->
        ^(While ^(CondExpr $cond) ^(Body $body))
    ;

// apeluri inlantuite
chain
    :    (atom d1=DOT tail ->
        ^($d1 ^(CallingObject atom) tail))
        ((DOT) => d2=DOT t=tail ->
        ^($d2 ^(CallingObject $chain) $t))*
    ;

fact
    :    (((atom DOT) => chain) | atom) ;

term
    :    fact ((MUL | DIV) => (MUL^ | DIV^) fact)*
    ;

sum
    :    term ((ADD | SUB) => (ADD | SUB)^ term)*
    ;

comp
    :    sum ((LE | GE | EQ | LT | GT) => (LE^ | GE^ | EQ^ | LT^ | GT^) sum)?
    ;

logical
    :    NOT^? comp
    ;

expr
    :    ID AS^ expr
    |    logical
    |    KW_VAR name=ID COLON type=ID (AS expr)? -> ^(LocalVar ^(Name $name) ^(Type $type) ^(InitExpr expr)?)
    ;

tail
    :    ID LPAREN (expr (COMMA expr)*)? RPAREN -> ^(CalledMethod ID) ^(LPAREN (expr+)?) ;

KW_CLASS
    :    'class'
    ;
KW_DEF
    :    'def'
    ;
KW_ELSE
    :    'else'
    ;
KW_EXTENDS
    :    'extends'
    ;
KW_FALSE
    :    'false'
    ;
KW_IF
    :    'if'
    ;
KW_NEW
    :    'new'
    ;
KW_OVERRIDE
    :    'override'
    ;
KW_THIS
    :    'this'
    ;
KW_TRUE
    :    'true'
    ;
KW_VAR
    :    'var'
    ;
KW_WHILE
    :    'while'
    ;

ID    :    ('a'..'z' | 'A'..'Z') (LETTER | DIGIT | '_')* ;

LPAREN
    :    '(' ;
RPAREN
    :    ')' ;
LEFT_BRACE
    :    '{' ;
RIGHT_BRACE
    :    '}' ;
COLON
    :    ':' ;
SEMICOLON
    :    ';' ;
DOT    :    '.' ;
COMMA
    :    ',' ;
ADD    :    '+' ;
SUB    :    '-' ;
MUL    :    '*' ;
DIV    :    '/' ;
NEG    :    '~' ;
LT    :    '<' ;
GT    :    '>' ;
LE    :    '<=' ;
GE    :    '>=' ;
EQ    :    '==' ;
AS    :    '=' ;
NOT    :    '!' ;

L_INT
    :    DIGIT+ ;
L_STRING
    :    QT ( ESC_SEQ | ~('\\'|'"'|'\n') )* QT ;

fragment LETTER
    :    'A'..'Z' | 'a'..'z' ;
fragment DIGIT
    :    '0'..'9' ;
fragment ESC_SEQ
    :   '\\' .
    ;
fragment QT
    :    '"' ;

WS    :    (' ' | '\f' | '\r' | '\t')+ { skip(); } ;
NEWLINE
    :    '\r'? '\n' { skip(); } ;
